#pragma once

#include <linux/spinlock_types.h>
#include <linux/lockdep.h>
#include <linux/irqflags.h>
#include <asm/barrier.h>

/*
 * Pull the arch_spin*() functions/declarations (UP-nondebug doesn't need them):
 */
#ifdef CONFIG_SMP
#include <asm/spinlock.h>
#else

#endif

void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
                          struct lock_class_key *key, short inner);
void _raw_spin_lock(raw_spinlock_t *lock);
void _raw_spin_unlock(raw_spinlock_t *lock);
unsigned long _raw_spin_lock_irqsave(raw_spinlock_t *lock);
void _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long flags);
void _raw_spin_lock_irq(raw_spinlock_t *lock);
void _raw_spin_unlock_irq(raw_spinlock_t *lock);
int _raw_spin_trylock(raw_spinlock_t *lock);

#define raw_spin_unlock(lock) _raw_spin_unlock(lock)

#define raw_spin_lock_irqsave(lock, flags)    \
    do                                        \
    {                                         \
        flags = _raw_spin_lock_irqsave(lock); \
    } while (0)

#define raw_spin_unlock_irqrestore(lock, flags)   \
    do                                            \
    {                                             \
        _raw_spin_unlock_irqrestore(lock, flags); \
    } while (0)

#define raw_spin_lock_init(lock)                                   \
    do                                                             \
    {                                                              \
        static struct lock_class_key __key;                        \
                                                                   \
        __raw_spin_lock_init((lock), #lock, &__key, LD_WAIT_SPIN); \
    } while (0)

#define raw_spin_lock(lock) _raw_spin_lock(lock)

#define raw_spin_unlock_irq(lock) _raw_spin_unlock_irq(lock)
#define raw_spin_lock_irq(lock) _raw_spin_lock_irq(lock)

/*
 * Always evaluate the 'subclass' argument to avoid that the compiler
 * warns about set-but-not-used variables when building with
 * CONFIG_DEBUG_LOCK_ALLOC=n and with W=1.
 */
#define raw_spin_lock_nested(lock, subclass) \
    _raw_spin_lock(lock)

static inline void spin_lock(spinlock_t *lock)
{
    raw_spin_lock(&lock->rlock);
}

static inline void spin_unlock(spinlock_t *lock)
{
    raw_spin_unlock(&lock->rlock);
}

#define raw_spin_trylock(lock) _raw_spin_trylock(lock)

#define spin_lock_init(lock) __raw_spin_lock_init(&((lock)->rlock), #lock, NULL, 0)

#define spin_lock_irqsave(lock, flags)                      \
    do                                                      \
    {                                                       \
        raw_spin_lock_irqsave(&((lock)->rlock), flags); \
    } while (0)

static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
{
    raw_spin_unlock_irqrestore(&lock->rlock, flags);
}
